// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support for request discovery
// feature: agent for vbs
// feature: content filter topic
// feature: Unified Transport Abstraction Layer Unified Transport Abstraction Layer
// feature: discovery support client and server
// feature: change idl check from md5 to crc16
// feature: add dynamic type lookup service
// ------------------------------------------------------------------

#include <edds/rtps/builtin/data/ReaderProxyData.h>

#include <edds/rtps/common/CDRMessage_t.h>
#include <transport/TransportFactory.hpp>
#include <elog/Log.hpp>
#include <edds/dds/core/policy/ParameterList.hpp>
#include <edds/dds/core/policy/QosPoliciesSerializer.hpp>
#include "xmlparser/xmlutils/DSFLocator.hpp"

#include "ProxyDataFilters.hpp"
#include <rtps/participant/RTPSParticipantImpl.h>

using ParameterList = evbs::edds::dds::ParameterList;

namespace evbs {
namespace ertps {
namespace rtps {

ReaderProxyData::ReaderProxyData(const size_t max_unicast_locators, const size_t max_multicast_locators)
#if HAVE_SECURITY
    : security_attributes_(0UL),
      plugin_security_attributes_(0UL),
      m_auth_token(),
      remote_locators_(max_unicast_locators, max_multicast_locators)
#else
    : remote_locators_(max_unicast_locators, max_multicast_locators)
#endif  // if HAVE_SECURITY
      ,
      m_userDefinedId(0U),
      m_isAlive(true),
      m_topicKind(NO_KEY),
      is_request_enable_(false) {
}

ReaderProxyData::ReaderProxyData(const size_t max_unicast_locators, const size_t max_multicast_locators,
                                 const VariableLengthDataLimits& data_limits)
    : ReaderProxyData(max_unicast_locators, max_multicast_locators) {
    m_qos.m_partition.set_max_size(static_cast<uint32_t>(data_limits.max_partitions));
    m_properties.set_max_size(static_cast<uint32_t>(data_limits.max_properties));
}

ReaderProxyData::~ReaderProxyData() {
    logDebug(RTPS_PROXY_DATA, "ReaderProxyData destructor guid:" << m_guid << " topicname: " << topicName(););
}

ReaderProxyData::ReaderProxyData(const ReaderProxyData& readerInfo)
#if HAVE_SECURITY
    : security_attributes_(readerInfo.security_attributes_),
      plugin_security_attributes_(readerInfo.plugin_security_attributes_),
      m_auth_token(),
      m_guid(readerInfo.m_guid)
#else
    : m_guid(readerInfo.m_guid)
#endif  // if HAVE_SECURITY
      ,
      remote_locators_(readerInfo.remote_locators_),
      m_key(readerInfo.m_key),
      m_RTPSParticipantKey(readerInfo.m_RTPSParticipantKey),
      m_typeName(readerInfo.m_typeName),
      m_topicName(readerInfo.m_topicName),
      m_userDefinedId(readerInfo.m_userDefinedId),
      m_isAlive(readerInfo.m_isAlive),
      m_topicKind(readerInfo.m_topicKind),
      m_properties(readerInfo.m_properties),
      content_filter_(readerInfo.content_filter_),
      is_request_enable_(readerInfo.is_request_enable_) {
    m_qos.setQos(readerInfo.m_qos, true);
}

ReaderProxyData& ReaderProxyData::operator=(const ReaderProxyData& readerInfo) {
#if HAVE_SECURITY
    security_attributes_ = readerInfo.security_attributes_;
    plugin_security_attributes_ = readerInfo.plugin_security_attributes_;
    m_auth_token = readerInfo.m_auth_token;
#endif  // if HAVE_SECURITY
    m_guid = readerInfo.m_guid;
    remote_locators_ = readerInfo.remote_locators_;
    m_key = readerInfo.m_key;
    m_RTPSParticipantKey = readerInfo.m_RTPSParticipantKey;
    m_typeName = readerInfo.m_typeName;
    m_topicName = readerInfo.m_topicName;
    m_userDefinedId = readerInfo.m_userDefinedId;
    m_isAlive = readerInfo.m_isAlive;
    m_topicKind = readerInfo.m_topicKind;
    m_qos.setQos(readerInfo.m_qos, true);
    m_properties = readerInfo.m_properties;
    content_filter_ = readerInfo.content_filter_;
    m_crc16Idl = readerInfo.m_crc16Idl;
    is_request_enable_ = readerInfo.is_request_enable_;
    m_type_plain = readerInfo.m_type_plain;
    m_hostId = readerInfo.m_hostId;
    return *this;
}

uint32_t ReaderProxyData::get_serialized_size(bool include_encapsulation) const {
    uint32_t ret_val = include_encapsulation ? 4U : 0U;

    // PID_UNICAST_LOCATOR
    ret_val += static_cast<uint32_t>((4U + PARAMETER_LOCATOR_LENGTH) * remote_locators_.unicast.size());

    // PID_MULTICAST_LOCATOR
    ret_val += static_cast<uint32_t>((4U + PARAMETER_LOCATOR_LENGTH) * remote_locators_.multicast.size());

    // PID_PARTICIPANT_GUID
    ret_val += 4U + PARAMETER_GUID_LENGTH;

    // PID_TOPIC_NAME
    ret_val += edds::dds::ParameterSerializer<Parameter_t>::cdr_serialized_size(m_topicName);

    // PID_TYPE_NAME
    ret_val += edds::dds::ParameterSerializer<Parameter_t>::cdr_serialized_size(m_typeName);

    // PID_KEY_HASH
    ret_val += 4U + 16U;

    // PID_ENDPOINT_GUID
    ret_val += 4U + PARAMETER_GUID_LENGTH;

    // PID_PROTOCOL_VERSION
    ret_val += 4U + 4U;

    // PID_VENDORID
    ret_val += 4U + 4U;

    // if (m_qos.m_durability.hasChanged)
    { ret_val += edds::dds::QosPoliciesSerializer<DurabilityQosPolicy>::cdr_serialized_size(m_qos.m_durability); }
    // if (m_qos.m_deadline.hasChanged)
    { ret_val += edds::dds::QosPoliciesSerializer<DeadlineQosPolicy>::cdr_serialized_size(m_qos.m_deadline); }
    // if (m_qos.m_liveliness.hasChanged)
    { ret_val += edds::dds::QosPoliciesSerializer<LivelinessQosPolicy>::cdr_serialized_size(m_qos.m_liveliness); }
    // if (m_qos.m_reliability.hasChanged)
    { ret_val += edds::dds::QosPoliciesSerializer<ReliabilityQosPolicy>::cdr_serialized_size(m_qos.m_reliability); }
    // if (m_qos.m_ownership.hasChanged)
    { ret_val += edds::dds::QosPoliciesSerializer<OwnershipQosPolicy>::cdr_serialized_size(m_qos.m_ownership); }
    if (m_qos.m_partition.hasChanged) {
        ret_val += edds::dds::QosPoliciesSerializer<PartitionQosPolicy>::cdr_serialized_size(m_qos.m_partition);
    }

    if (m_properties.size() > 0U) {
        // PID_PROPERTY_LIST
        ret_val += edds::dds::ParameterSerializer<ParameterPropertyList_t>::cdr_serialized_size(m_properties);
    }

    // string m_crc16Idl
    ret_val += evbs::edds::dds::ParameterSerializer<Parameter_t>::cdr_serialized_size(m_crc16Idl);

    // PID_E2E_PROTECTION
    ret_val += 4U + PARAMETER_E2E_ENABLE_LENGTH;

    // PID_CONTENT_FILTER_PROPERTY
    // Take into count only when filter_class_name and filter_expression are not empty.
    if (0 < content_filter_.filter_class_name.size() && 0 < content_filter_.filter_expression.size()) {
        ret_val += edds::dds::ParameterSerializer<ContentFilterProperty>::cdr_serialized_size(content_filter_);
    }

    // PID_TYPE_PLAIN
    ret_val += 4U + PARAMETER_BOOL_LENGTH;
#if HAVE_SECURITY
    if ((this->security_attributes_ != 0UL) || (this->plugin_security_attributes_ != 0UL)) {
        ret_val += 4U + PARAMETER_ENDPOINT_SECURITY_INFO_LENGTH;
    }
#endif  // if HAVE_SECURITY

    // PID_SENTINEL
    return ret_val + 4U;
}

bool ReaderProxyData::writeToCDRMessage(CDRMessage_t* msg, bool write_encapsulation) const {
    if (write_encapsulation) {
        if (!ParameterList::writeEncapsulationToCDRMsg(msg)) {
            return false;
        }
    }

    for (const Locator_t& locator : remote_locators_.unicast) {
        ParameterLocator_t p(edds::dds::PID_UNICAST_LOCATOR, PARAMETER_LOCATOR_LENGTH, locator);
        if (!edds::dds::ParameterSerializer<ParameterLocator_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    for (const Locator_t& locator : remote_locators_.multicast) {
        ParameterLocator_t p(edds::dds::PID_MULTICAST_LOCATOR, PARAMETER_LOCATOR_LENGTH, locator);
        if (!edds::dds::ParameterSerializer<ParameterLocator_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterGuid_t p(edds::dds::PID_PARTICIPANT_GUID, PARAMETER_GUID_LENGTH, m_RTPSParticipantKey);
        if (!edds::dds::ParameterSerializer<ParameterGuid_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterString_t p(edds::dds::PID_TOPIC_NAME, 0U, m_topicName);
        if (!edds::dds::ParameterSerializer<ParameterString_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterString_t p(edds::dds::PID_TYPE_NAME, 0U, m_typeName);
        if (!edds::dds::ParameterSerializer<ParameterString_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterKey_t p(edds::dds::PID_KEY_HASH, 16U, m_key);
        if (!edds::dds::ParameterSerializer<ParameterKey_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterGuid_t p(edds::dds::PID_ENDPOINT_GUID, PARAMETER_GUID_LENGTH, m_guid);
        if (!edds::dds::ParameterSerializer<ParameterGuid_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterProtocolVersion_t p(edds::dds::PID_PROTOCOL_VERSION, 4U);
        if (!edds::dds::ParameterSerializer<ParameterProtocolVersion_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    {
        ParameterVendorId_t p(edds::dds::PID_VENDORID, 4U);
        if (!edds::dds::ParameterSerializer<ParameterVendorId_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
    // if (m_qos.m_durability.hasChanged)
    {
        if (!edds::dds::QosPoliciesSerializer<DurabilityQosPolicy>::add_to_cdr_message(m_qos.m_durability, msg)) {
            return false;
        }
    }
    // if (m_qos.m_deadline.hasChanged)
    {
        if (!edds::dds::QosPoliciesSerializer<DeadlineQosPolicy>::add_to_cdr_message(m_qos.m_deadline, msg)) {
            return false;
        }
    }
    // if (m_qos.m_liveliness.hasChanged)
    {
        if (!edds::dds::QosPoliciesSerializer<LivelinessQosPolicy>::add_to_cdr_message(m_qos.m_liveliness, msg)) {
            return false;
        }
    }
    // if (m_qos.m_reliability.hasChanged)
    {
        if (!edds::dds::QosPoliciesSerializer<ReliabilityQosPolicy>::add_to_cdr_message(m_qos.m_reliability, msg)) {
            return false;
        }
    }
    // if (m_qos.m_ownership.hasChanged)
    {
        if (!edds::dds::QosPoliciesSerializer<OwnershipQosPolicy>::add_to_cdr_message(m_qos.m_ownership, msg)) {
            return false;
        }
    }

    if (m_qos.m_partition.hasChanged) {
        if (!edds::dds::QosPoliciesSerializer<PartitionQosPolicy>::add_to_cdr_message(m_qos.m_partition, msg)) {
            return false;
        }
    }

    if (m_properties.size() > 0) {
        if (!edds::dds::ParameterSerializer<ParameterPropertyList_t>::add_to_cdr_message(m_properties, msg)) {
            return false;
        }
    }

    {
        // string m_crc16Idl
        ParameterString_t p_crc16(edds::dds::PID_CRC16_IDL, 0U, m_crc16Idl);
        (void)evbs::edds::dds::ParameterSerializer<ParameterString_t>::add_to_cdr_message(p_crc16, msg);
    }

    {
        ParameterE2eProtection_t p(edds::dds::PID_E2E_PROTECTION, PARAMETER_E2E_ENABLE_LENGTH,
                                   static_cast<uint32_t>(m_qos.m_e2eProtecion.enabled));
        if (!edds::dds::ParameterSerializer<ParameterE2eProtection_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }

    // Serialize ContentFilterProperty only when filter_class_name and filter_expression are not empty.
    if (0 < content_filter_.filter_class_name.size() && 0 < content_filter_.filter_expression.size()) {
        if (!edds::dds::ParameterSerializer<ContentFilterProperty>::add_to_cdr_message(content_filter_, msg)) {
            return false;
        }
    }

    if (m_qos.m_agent_flag != 0) {
        if (!ParameterList::writeUint32ToCDRMsg(msg, edds::dds::PID_AGENT_ENDPOINT, 4, m_qos.m_agent_flag)) {
            return false;
        }
    }

    if (m_type_plain) {
        ParameterBool_t p(edds::dds::PID_TYPE_PLAIN, PARAMETER_BOOL_LENGTH, true);
        if (!edds::dds::ParameterSerializer<ParameterBool_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }

#if HAVE_SECURITY
    if ((security_attributes_ != 0UL) || (plugin_security_attributes_ != 0UL)) {
        ParameterEndpointSecurityInfo_t p;
        p.security_attributes = security_attributes_;
        p.plugin_security_attributes = plugin_security_attributes_;
        if (!edds::dds::ParameterSerializer<ParameterEndpointSecurityInfo_t>::add_to_cdr_message(p, msg)) {
            return false;
        }
    }
#endif  // if HAVE_SECURITY
    return edds::dds::ParameterSerializer<Parameter_t>::add_parameter_sentinel(msg);
}

bool ReaderProxyData::readFromCDRMessage(CDRMessage_t* msg_cdr, RTPSParticipantImpl* localParticipant) {
    bool are_shm_default_locators_present = false;
    bool is_shm_transport_possible = false;
    bool is_shm_transport_available = localParticipant->has_shm_transport();

    auto param_process = [this, localParticipant, &is_shm_transport_available, &is_shm_transport_possible,
                          &are_shm_default_locators_present](CDRMessage_t* msg, const ParameterId_t& pid,
                                                             uint16_t plength) {
        switch (pid) {
            case edds::dds::PID_VENDORID: {
                ParameterVendorId_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterVendorId_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                is_shm_transport_available &= (p.vendorId == c_VendorId_vbs);
                break;
            }
            case edds::dds::PID_DURABILITY: {
                if (!edds::dds::QosPoliciesSerializer<DurabilityQosPolicy>::read_from_cdr_message(m_qos.m_durability,
                                                                                                  msg, plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_DEADLINE: {
                if (!edds::dds::QosPoliciesSerializer<DeadlineQosPolicy>::read_from_cdr_message(m_qos.m_deadline, msg,
                                                                                                plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_LIVELINESS: {
                if (!edds::dds::QosPoliciesSerializer<LivelinessQosPolicy>::read_from_cdr_message(m_qos.m_liveliness,
                                                                                                  msg, plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_RELIABILITY: {
                if (!edds::dds::QosPoliciesSerializer<ReliabilityQosPolicy>::read_from_cdr_message(m_qos.m_reliability,
                                                                                                   msg, plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_OWNERSHIP: {
                if (!edds::dds::QosPoliciesSerializer<OwnershipQosPolicy>::read_from_cdr_message(m_qos.m_ownership, msg,
                                                                                                 plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_PARTITION: {
                if (!edds::dds::QosPoliciesSerializer<PartitionQosPolicy>::read_from_cdr_message(m_qos.m_partition, msg,
                                                                                                 plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_TOPIC_NAME: {
                ParameterString_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterString_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                m_topicName = p.getName();
                break;
            }
            case edds::dds::PID_TYPE_NAME: {
                ParameterString_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterString_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                m_typeName = p.getName();
                break;
            }
            case edds::dds::PID_PARTICIPANT_GUID: {
                ParameterGuid_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterGuid_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                m_RTPSParticipantKey = p.guid;
                break;
            }
            case edds::dds::PID_ENDPOINT_GUID: {
                ParameterGuid_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterGuid_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                m_guid = p.guid;
                m_key = p.guid;
                break;
            }
            case edds::dds::PID_UNICAST_LOCATOR: {
                ParameterLocator_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterLocator_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }
                elogInfo(RTPS_READER_PROXY,
                         "Remote reader Locator carried in the message: " << p.locator << " guid: " << m_guid);
                if (p.locator.kind == LOCATOR_KIND_SHM) {
                    break;
                }
                if (p.locator.kind == LOCATOR_KIND_DSF) {
                    remote_locators_.add_unicast_locator(p.locator);
                    break;
                } else if (p.locator.kind == LOCATOR_KIND_UDS) {
                    bool bRegistered = localParticipant->registed_user_transport(
                        vbs::RemoteEndpointInfo::LocatorType::LOCATOR_TYPE_UDS);
                    if (!bRegistered) {
                        remote_locators_.add_unicast_locator(p.locator);
                        break;
                    }
                    is_filtered(vbs::RemoteEndpointInfo::LocatorType::LOCATOR_TYPE_UDS, true);
                } else if (p.locator.kind == LOCATOR_KIND_UDPv4) {
                    bool bRegistered = localParticipant->registed_user_transport(
                        vbs::RemoteEndpointInfo::LocatorType::LOCATOR_TYPE_UDP);
                    if (!bRegistered) {
                        remote_locators_.add_unicast_locator(p.locator);
                        break;
                    }
                    is_filtered(vbs::RemoteEndpointInfo::LocatorType::LOCATOR_TYPE_UDP, true);
                }
                Locator_t temp_locator;
                if (localParticipant->network_factory()->transform_remote_locator(
                        localParticipant->get_transport_name(), p.locator, temp_locator) &&
                    localParticipant->is_valid_remote_locator(p.locator)) {
                    ProxyDataFilters::filter_locators(is_shm_transport_available, &is_shm_transport_possible,
                                                      &are_shm_default_locators_present, &remote_locators_,
                                                      temp_locator, true);
                }
                break;
            }
            case edds::dds::PID_MULTICAST_LOCATOR: {
                ParameterLocator_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterLocator_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                Locator_t temp_locator;
                if (localParticipant->network_factory()->transform_remote_locator(
                        localParticipant->get_transport_name(), p.locator, temp_locator)) {
                    ProxyDataFilters::filter_locators(is_shm_transport_available, &is_shm_transport_possible,
                                                      &are_shm_default_locators_present, &remote_locators_,
                                                      temp_locator, false);
                }
                break;
            }
            case edds::dds::PID_KEY_HASH: {
                ParameterKey_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterKey_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                m_key = p.key;
                vbsutil::xmlparser::iHandle2GUID(m_guid, m_key);
                break;
            }
            case edds::dds::PID_CONTENT_FILTER_PROPERTY: {
                if (!edds::dds::ParameterSerializer<ContentFilterProperty>::read_from_cdr_message(content_filter_, msg,
                                                                                                  plength)) {
                    return false;
                }
                break;
            }
#if HAVE_SECURITY
            case edds::dds::PID_ENDPOINT_SECURITY_INFO: {
                ParameterEndpointSecurityInfo_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterEndpointSecurityInfo_t>::read_from_cdr_message(p, msg,
                                                                                                            plength)) {
                    return false;
                }

                security_attributes_ = p.security_attributes;
                plugin_security_attributes_ = p.plugin_security_attributes;
                break;
            }
#endif  // if HAVE_SECURITY
            case edds::dds::PID_PROPERTY_LIST: {
                if (!edds::dds::ParameterSerializer<ParameterPropertyList_t>::read_from_cdr_message(m_properties, msg,
                                                                                                    plength)) {
                    return false;
                }
                break;
            }
            case edds::dds::PID_CRC16_IDL: {
                plength = 12U;
                ParameterString_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterString_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }

                std::string crc16_input = p.getName();
                setIdlCrc16(std::move(crc16_input));
                break;
            }
            case edds::dds::PID_E2E_PROTECTION: {
                m_qos.m_e2eProtecion.needCheckEnableFlag = true;
                plength = PARAMETER_E2E_ENABLE_LENGTH;
                ParameterE2eProtection_t p(pid, plength);
                if (!edds::dds::ParameterSerializer<ParameterE2eProtection_t>::read_from_cdr_message(p, msg, plength)) {
                    return false;
                }
                m_qos.m_e2eProtecion.enabled = static_cast<bool>(p.e2eEnable);
                break;
            }
            case edds::dds::PID_AGENT_ENDPOINT: {
                uint32_t agent_flag = 0;
                if (plength != PARAMETER_AGENT_FLAG_LENGTH) {
                    return false;
                }
                if (!ertps::rtps::CDRMessage::readUInt32(msg, &agent_flag)) {
                    return false;
                }
                m_qos.m_agent_flag = agent_flag & 0xff;
                break;
            }
            case edds::dds::PID_TYPE_PLAIN: {
                if (plength != PARAMETER_BOOL_LENGTH) {
                    return false;
                }
                uint32_t type;
                if (!ertps::rtps::CDRMessage::readUInt32(msg, &type)) {
                    return false;
                }
                if (type > 0) {
                    m_type_plain = true;
                }
                break;
            }
            default: {
                break;
            }
        }

        return true;
    };

    uint32_t qos_size;
    clear();
    try {
        if (ParameterList::readParameterListfromCDRMsg(*msg_cdr, param_process, true, qos_size)) {
            if (m_guid.entityId.value[3] == 0x04U) {
                m_topicKind = NO_KEY;
            } else if (m_guid.entityId.value[3] == 0x07U) {
                m_topicKind = WITH_KEY;
            }

            /* Some vendors (i.e. CycloneDDS) do not follow DDSI-RTPS and omit PID_PARTICIPANT_GUID
             * In that case we use a default value relying on the prefix from m_guid and the default
             * participant entity id
             */
            if (!m_RTPSParticipantKey.isDefined()) {
                GUID_t tmp_guid = m_guid;
                tmp_guid.entityId = c_EntityId_RTPSParticipant;
                m_RTPSParticipantKey = tmp_guid;
            }

            return true;
        }
    } catch (std::bad_alloc& ba) {
        elogWarning(XTYPES, "readFromCDRMessage(Reader proxy) " << m_topicName << " bad_alloc caught: " << ba.what());
    }

    return false;
}

void ReaderProxyData::clear() {
#if HAVE_SECURITY
    security_attributes_ = 0UL;
    plugin_security_attributes_ = 0UL;
    m_auth_token.reset();
#endif  // if HAVE_SECURITY
    m_guid = c_Guid_Unknown;
    remote_locators_.unicast.clear();
    remote_locators_.multicast.clear();
    m_key = InstanceHandle_t();
    m_RTPSParticipantKey = InstanceHandle_t();
    m_typeName = "";
    m_topicName = "";
    m_userDefinedId = 0U;
    m_isAlive = true;
    m_topicKind = NO_KEY;
    m_qos.clear();
    m_properties.clear();
    m_properties.length = 0U;

    content_filter_.filter_class_name = "";
    content_filter_.content_filtered_topic_name = "";
    content_filter_.related_topic_name = "";
    content_filter_.filter_expression = "";
    content_filter_.expression_parameters.clear();

    m_crc16Idl = "";

    is_request_enable(false);

    m_type_plain = false;
    set_host_id(0);
    set_pid(0);
}

bool ReaderProxyData::is_update_allowed(const ReaderProxyData& rdata) const {
    if ((m_guid != rdata.m_guid) ||
#if HAVE_SECURITY
        (security_attributes_ != rdata.security_attributes_) ||
        (plugin_security_attributes_ != rdata.security_attributes_) ||
#endif  // if HAVE_SECURITY
        (m_typeName != rdata.m_typeName) || (m_topicName != rdata.m_topicName)) {
        return false;
    }

    return m_qos.canQosBeUpdated(rdata.m_qos);
}

void ReaderProxyData::update(ReaderProxyData* rdata) {
    remote_locators_ = rdata->remote_locators_;
    m_qos.setQos(rdata->m_qos, false);
    m_isAlive = rdata->m_isAlive;
    content_filter_ = rdata->content_filter_;
    is_request_enable_ = rdata->is_request_enable_;
    set_host_id(rdata->m_hostId);
    set_pid(rdata->m_pid);
}

void ReaderProxyData::copy(ReaderProxyData* rdata) {
#if HAVE_SECURITY
    m_auth_token = rdata->m_auth_token;
#endif
    m_guid = rdata->m_guid;
    remote_locators_ = rdata->remote_locators_;
    m_key = rdata->m_key;
    m_RTPSParticipantKey = rdata->m_RTPSParticipantKey;
    m_typeName = rdata->m_typeName;
    m_topicName = rdata->m_topicName;
    m_userDefinedId = rdata->m_userDefinedId;
    m_qos = rdata->m_qos;
    m_isAlive = rdata->m_isAlive;
    m_topicKind = rdata->m_topicKind;
    m_properties = rdata->m_properties;
    m_crc16Idl = rdata->m_crc16Idl;
    content_filter_ = rdata->content_filter_;
    m_type_plain = rdata->m_type_plain;
    is_request_enable_ = rdata->is_request_enable_;
    set_host_id(rdata->m_hostId);
    set_pid(rdata->m_pid);
}

void ReaderProxyData::add_unicast_locator(const Locator_t& locator) {
    remote_locators_.add_unicast_locator(locator);
}

void ReaderProxyData::set_announced_unicast_locators(const LocatorList_t& locators) {
    remote_locators_.unicast.clear();
    for (const Locator_t& locator : locators) {
        logDebug(RTPS_PROXY_DATA, "set_announced_unicast_locators " << locator);
        remote_locators_.add_unicast_locator(locator);
    }
}

void ReaderProxyData::set_remote_unicast_locators(const LocatorList_t& locators, RTPSParticipantImpl* participant) {
    Locator_t local_locator;
    remote_locators_.unicast.clear();
    for (const Locator_t& locator : locators) {
        if (participant->network_factory()->transform_remote_locator(participant->get_transport_name(), locator,
                                                                     local_locator)) {
            remote_locators_.add_unicast_locator(local_locator);
        }
    }
}

void ReaderProxyData::add_multicast_locator(const Locator_t& locator) {
    remote_locators_.add_multicast_locator(locator);
}

void ReaderProxyData::set_multicast_locators(const LocatorList_t& locators, RTPSParticipantImpl* participant) {
    Locator_t local_locator;
    remote_locators_.multicast.clear();
    for (const Locator_t& locator : locators) {
        if (participant->network_factory()->transform_remote_locator(participant->get_transport_name(), locator,
                                                                     local_locator)) {
            remote_locators_.add_multicast_locator(locator);
        }
    }
}

void ReaderProxyData::set_locators(const RemoteLocatorList& locators) {
    remote_locators_ = locators;
}

void ReaderProxyData::set_remote_locators(const RemoteLocatorList& locators, RTPSParticipantImpl* participant,
                                          bool use_multicast_locators) {
    Locator_t local_locator;
    remote_locators_.unicast.clear();
    remote_locators_.multicast.clear();

    for (const Locator_t& locator : locators.unicast) {
        if (participant->network_factory()->transform_remote_locator(participant->get_transport_name(), locator,
                                                                     local_locator)) {
            remote_locators_.add_unicast_locator(local_locator);
        }
    }

    if (use_multicast_locators) {
        for (const Locator_t& locator : locators.multicast) {
            if (participant->network_factory()->transform_remote_locator(participant->get_transport_name(), locator,
                                                                         local_locator)) {
                remote_locators_.add_multicast_locator(locator);
            }
        }
    }
}

RTPS_DllAPI void ReaderProxyData::has_udp_dsf_locators(bool& take_udp_locator, uint32_t& queue_id) {
    take_udp_locator = false;
    bool found_dsf = false;
    for (auto& loc : remote_locators_.unicast) {
        if (!take_udp_locator && loc.kind == LOCATOR_KIND_UDPv4) {
            take_udp_locator = true;
        } else if (!found_dsf && loc.kind == LOCATOR_KIND_DSF) {
            uint32_t pool_id;
            found_dsf = true;
            DSFLocator::get_locator_information(loc, pool_id, queue_id);
        }

        if (take_udp_locator && found_dsf) {
            break;
        }
    }
}

void ReaderProxyData::is_filtered(vbs::RemoteEndpointInfo::LocatorType type, bool filter) {
    is_filtered_[type] = filter;
}

bool ReaderProxyData::is_filtered(vbs::RemoteEndpointInfo::LocatorType type) const {
    return is_filtered_[type];
}

void ReaderProxyData::is_request_enable(bool enable) {
    is_request_enable_ = enable;
}

bool ReaderProxyData::is_request_enable() const {
    return is_request_enable_;
}
} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */
